<?php
namespace system\libraries;

use system\core\Config;
use system\core\Loader;
use system\core\Request;

/**
 * Template Library
 * 
 * This Template Library uses regions as placeholders. You can set multiple 
 * templates, by defining them in the "template.php" config file.
 * 
 * @author Steffen Brem <steffenbrem@gmail.com>
 * @package System.libraries
 */
class Template 
{
    private $_config;
    private $_master;
    private $_template;
   
    private $_regions = array(
        '_scripts' => '',
        '_styles' => ''
    );
    
    private $_output;
    private $_load;
    
    private $_disabled = FALSE;
    
    /**
     * Singleton
     * 
     * @var System\Libraries\Template
     */
    public static $_instance;


    /**
     * Constructor
     * 
     * Set a template group as parameter
     * 
     * @param string $group 
     */
    private function __construct()
    {
        $this->_config = Config::get('template');

        $this->_load = new Loader();

        $this->setTemplate($this->_config['active']);

        self::$_instance = $this;
    }
    
    /**
     * Singleton
     *
     * @return \System\Libraries\Template
     */
    public static function getInstance()
    {
        if ( ! self::$_instance instanceof Template )
        {
            self::$_instance = new Template();
        }
        
        // If auto rendering is disabled, we do not return this instance...
        if ( self::$_instance->_disabled === TRUE ) 
        { 
            return FALSE;
        }
        
        return self::$_instance;
    }
    
    /**
     * Set the template group
     * 
     * @param string $group 
     */
    public function setTemplate( $group )
    {
        if ( isset($this->_config[$group]) )
        {
            $this->_template = $this->_config[$group];
            
            // Reset Regions
            $this->_regions = $_regions = array(
                '_scripts' => '',
                '_styles' => ''
            );
            
            $this->initialize($this->_template);            
        }
        else
        {
            throw new \Exception('The template group "' . $group . '" does not exist.');
        }
    }
    
    /**
     * Initialize
     * 
     * Set's the master template and regions.
     * 
     * @param array $template
     */
    private function initialize( $template )
    {
        if ( isset($template['template']) )
        {
            $filePath = APP_PATH . 'templates/' . $template['template'] . '.phtml';
            
            $request = Request::getInstance();
            if ( $request instanceof Request && $request->getModule() )
            {
                $filePath = APP_PATH . 'modules/' . $request->getModule() . '/templates/' . $template['template'] . '.phtml';
            }
            
            if ( file_exists($filePath) )
            {
                $this->_master = $template['template'];
            }
            else
            {
                throw new \Exception('Template file "' . $template['template'] . '.phtml" does not exist in the "templates" folder.');
            }
        }
        else
        {
            throw new \Exception('Template is not set correctly. Please check the config file "template.php" and correct this.');
        }
        
        // Set regions
        if ( isset($template['regions']) )
        {
            $this->setRegions($template['regions']);
        }
    }
    
    /**
     * Add regions to the regions property
     * 
     * @param array $regions 
     */
    public function setRegions( $regions )
    {
        if ( ! is_array($regions) )
        {
            $regions = array($regions);
        }
        
        if ( count($regions) )
        {
            foreach ( $regions as $key => $region )
            {
                if ( ! is_array($region) )
                {
                    $this->addRegion($region);
                }
                else
                {
                    $this->addRegion($key, $region);
                }
            }
        }
    }
    
    /**
     * Add one region to the regions property
     * 
     * @param type $region
     * @param array $data 
     */
    public function addRegion( $region, $data = array(), $overwrite = FALSE )
    {
        if ( ! is_array($data) )
        {
            $data = array();
        }

        if ( $overwrite === TRUE || ! isset($this->_regions[$region]) )
        {
            $this->_regions[$region] = $data;
        }
        else
        {
            throw new \Exception('The region "' . $region . '" already has been defined.');
        }
    }
    
    /**
     * Write text to a region, defined in your template.
     * 
     * @param string $region
     * @param string $content
     */
    public function write( $region, $content )
    {
        if ( isset($this->_regions[$region]) )
        {
            $this->_regions[$region][] = $content;
        }
        else
        {
            throw new \Exception('Cannot write to the "' . $region . '" region. Region is not defined.');
        }
    }
    
    /**
     * Write a view file to a region.
     * 
     * @param string $region
     * @param string $view
     * @param array $data
     */
    public function writeView( $region, $view, $data = array() )
    {
        $content = $this->_load->view($view, $data, TRUE);
        
        $this->write($region, $content);
    }
    
    /**
     * Add a CSS file to the $_styles region.
     * 
     * $type options:
     *  - local (if you have the css files on your server)
     *  - extern (if you access the css files outside your server)
     * 
     * @param string $path
     * @param string $type
     */
    public function addCss( $path, $type = 'local' )
    {
        if ( ! $path || ! preg_match('#^https?://#i', $path) )
        {
            if ( !file_exists($path) )
            {
                throw new \Exception('Could not load CSS file "' . $path . '", it does not exist.');
            }
            $path = Config::get('config', 'base_url') . $path;
        }
        
        $js = '<link type="text/css" href="' . $path . '" rel="stylesheet" />' . PHP_EOL;
        $this->write('_scripts', $js);
    }
    
    /**
     * Add a JS file to the $_scripts region.
     * 
     * $type options:
     *  - local (if you have the js file on your server)
     *  - extern (if you access the js file outside your server)
     * 
     * @param string $path
     * @param string $type
     */
    public function addJs( $path )
    {
        if ( ! $path || ! preg_match('#^https?://#i', $path) )
        {
            if ( !file_exists($path) )
            {
                throw new \Exception('Could not load Javascript file "' . $path . '", it does not exist.');
            }
            $path = Config::get('config', 'base_url') . $path;
        }
        
        $js = '<script type="text/javascript" src="' . $path . '"></script>' . PHP_EOL;
        $this->write('_scripts', $js);
    }
    
    /**
     * Render Template
     * 
     * When buffer is set to TRUE, it will return the output as a string.
     * 
     * @param string $region
     * @param bool $buffer
     */
    public function render( $region = NULL, $buffer = FALSE )
    {       
        foreach ( $this->_regions as $name => $region )
        {
            $this->_output[$name] = ( is_array($region) && key_exists('0', $region) ) ? $region['0'] : $region;
        }

        $this->_load->view($this->_master, $this->_output, FALSE, 'templates/');
    }
    
    /**
     * Disable auto rendering
     */
    public function disable()
    {
        $this->_disabled = TRUE;
    }
}

/* End of file Template.php */
